#include "NetworkManager.h"

#include "cocos2d.h"
#include "JsonObject.h"
#include "..\CCPlatformMacros.h"

NetworkManager* NetworkManager::sInstance = NULL;

size_t NetworkManager::process_data(void *buffer, size_t size, size_t nmemb, void *user_p)
{
	size_t return_size = size * nmemb;
	NetworkManager * con = static_cast<NetworkManager*>(user_p);

	if( con )
	{
		char * bytes = new char[return_size+1];
		memcpy( bytes, buffer, return_size );
		bytes[return_size] = 0;

		const char* strValue = (const char*)bytes;
		con->m_stringBuffer += strValue;

		delete []bytes;
	}
	return return_size;
}

size_t NetworkManager::process_binary_data(void* buffer, size_t size, size_t nmemb, void*user_p)
{
	size_t return_size = size * nmemb;
	NetworkManager * con = static_cast<NetworkManager*>(user_p);

	if( con )
	{
		if( con->m_binaryBuffer == NULL )
		{
			con->m_binaryBuffer = (unsigned char*)malloc(return_size);
		}
		else
		{
			con->m_binaryBuffer = (unsigned char*)realloc(con->m_binaryBuffer,con->m_binarySize + return_size);
		}

		memcpy( con->m_binaryBuffer + con->m_binarySize, buffer, return_size );

		con->m_binarySize	+= return_size;

	}
	return return_size;
}

NetworkManager::NetworkManager():m_pTarget(NULL)
	,m_sucfunc(NULL)
	,m_failfunc(NULL)
	,m_binaryBuffer(NULL)
	,m_binarySize(NULL)
{
	curl_global_init(CURL_GLOBAL_ALL);
	m_connection = curl_easy_init();
	init();
}

NetworkManager::~NetworkManager()
{
	curl_easy_cleanup(m_connection);
	curl_global_cleanup();
}

NetworkManager* NetworkManager::getInstance()
{
	if ( NULL == sInstance )
	{
		sInstance = new NetworkManager();
		sInstance->autorelease();
		sInstance->retain();
	}
	return sInstance;
}


int NetworkManager::curl_debug_callback (CURL* pCURL, curl_infotype infoType, char* szBuff, size_t size, void* param)
{
	return 0;
}

void NetworkManager::call( const char * method, CCObject* target, SEL_CallFuncO onSuccess, SEL_CallFuncO onFailed, const std::map<std::string,std::string>* bParams, bool bPost)
{
	std::string paraStr;
	bool bFirst = true;

	if(bParams)
	{
		for( std::map<std::string, std::string>::const_iterator iter = (*bParams).begin(); iter != (*bParams).end(); iter++ )
		{
			if( bFirst )
			{
				paraStr += iter->first;
				if(!(iter->second.empty()))
				{
					paraStr += "=" + iter->second;
				}
				bFirst = false;
			}
			else
			{
				paraStr += "&" + iter->first;
				if(!(iter->second.empty()))
				{
					paraStr += "=" + iter->second;
				}
			}
		}
	}	

	std::string url = "http://localhost:8081/";
	url += method;

	char* szURL = curl_easy_escape(m_connection, url.c_str(), url.length());

	CCLOG("%s %s?%s ", bPost ? "POST" : "GET", url.c_str(), paraStr.c_str());

	if(bPost)
	{
		url += "?";

		curl_easy_setopt(m_connection, CURLOPT_POST, 1);
		curl_easy_setopt(m_connection, CURLOPT_POSTFIELDS, paraStr.c_str());
	}
	else
	{
		url += "?";
		url += paraStr;
	}	

	curl_easy_setopt(m_connection, CURLOPT_URL, url.c_str());

	curl_easy_setopt(m_connection, CURLOPT_WRITEFUNCTION, &NetworkManager::process_data);
	curl_easy_setopt(m_connection, CURLOPT_WRITEDATA, this);

	m_stringBuffer.clear();

	CURLcode res = curl_easy_perform(m_connection);
	if ( CURLE_OK != res )
	{
		if( m_pTarget && m_failfunc )
		{
			(m_pTarget->*m_failfunc)(NULL);
		}
	}
	else
	{
		JsonObject* jsonobj = new JsonObject( m_stringBuffer );
		jsonobj->autorelease();

		if ( cheakError(jsonobj) )
		{
			if (target && onFailed )
			{
				(target->*onFailed)( jsonobj );
			}
		}
		else
		{
			if (target && onSuccess)
			{
				(target->*onSuccess)( jsonobj );
			}
		}
	}

	clearCallback();
}

CCObject* NetworkManager::getCallbackTarget()
{
	return m_pTarget;
}

cocos2d::SEL_CallFuncO NetworkManager::getCallbackSuc()
{
	return m_sucfunc;
}

cocos2d::SEL_CallFuncO NetworkManager::getCallbackFail()
{
	return m_failfunc;
}

bool NetworkManager::init()
{
	return true;
}

void NetworkManager::clearCallback()
{
	m_pTarget = NULL;
	m_sucfunc = NULL;
	m_failfunc = NULL;
}

bool NetworkManager::cheakError( JsonObject* serverData )
{
	Json::Value& jsonval = serverData->getJsonVal();
	if ( jsonval.has("msgType") )
	{
		int msgType = jsonval["msgType"].asInt();
		if ( msgType == Msg::Error )
		{
			return true;
		}
	}

	return false;
}
